<?php


namespace app\reception\logic;


use app\common\classes\BehaviorRedis;
use app\common\model\QuickApp;
use app\common\model\QuickUser;
use app\reception\classs\DouYinHelp;
use app\reception\classs\KsHelp;
use app\reception\server\MiHuaPayServer;
use GuzzleHttp\Client;
use think\Db;
use Yansongda\Pay\Pay;

class PayLogic
{


    /**
     * 生成订单号
     * @return string
     */
    public function generateOrderNumber()
    {
        $prefix = 'ORDX'; // 订单号前缀
        $timestamp = time(); // 当前时间戳
        $random = mt_rand(1000000, 9999999); // 随机数
        // 使用当前时间戳和随机数生成订单号
        $orderNumber = $prefix . $timestamp . $random;
        return $orderNumber;
    }


    /**
     * 下单
     * @param $orderData
     * @return \think\response\Json
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function callPayment($orderData, $isIAPY = 0)
    {
        $qa = QuickApp::get($orderData['quick_id']);
        switch ($qa->type) {
            case 1:
                $data = [
                    'skuList' => [
                        [
                            'skuId' => '1',
                            'price' => $orderData['total_fee'],
                            'quantity' => 1,
                            'title' => '书城付费阅读',
                            'imageList' => [config('img_domain').'/applet/logo.jpg'],
                            'type' => 401,
                            'tagGroupId' => 'tag_group_7272625659888041996'//$tag_result['data']['tag_detail_list'][0]['tag_group_id'],
                        ]
                    ],
                    'outOrderNo' => $orderData['out_trade_no'],
                    'totalAmount' => $orderData['total_fee'],
                    'payNotifyUrl' => $this->getNotifyUrl($qa),
                    'orderEntrySchema' => ['path' => 'pagesA/pay/pay'],
                    'merchantUid' => '72815570448159890520',
                ];
                $timestamp = time();
                $nonceStr = $this->randStr(10);
                $keyVersion = "4";
                $byteAuthorization = $this->getByteAuthorization(json_encode($data), $qa->appid, $nonceStr, $timestamp, $keyVersion);
                return sucJson(['data' => json_encode($data), 'byteAuthorization' => $byteAuthorization]);
                break;
            case 2:
                if ($isIAPY == 0) {
                    return $this->ksCreateOrder($qa, $orderData);
                }
                return $this->ksIAP($qa, $orderData);
                break;
            case 3:
                return $this->wxMiHuaCreateOrder($qa,$orderData);
                break;
            default:
                return $this->dyCreateOrder($qa, $orderData);
        }
    }

    private function wxMiHuaCreateOrder($qa,$orderData)
    {
        include_once('../application/reception/extend/MiHuaApi/config.php');
        include_once('../application/reception/extend/MiHuaApi/getSign.php');
        include_once('../application/reception/extend/MiHuaApi/getData.php');
        $openid = Db::table("quick_user_".$qa->id)->where("id",$orderData['uid'])->value('openid');
        $mihua = new MiHuaPayServer();
        $paymentNumber = $mihua->paymentNumber;
        $inputOrderData = array(
            'merAccount' => $paymentNumber['mer_account'],//商户标识
            'merNo' => $paymentNumber['mer_no'],//商户编号
            'time' => time(),//时间戳
            'orderId' => $orderData['out_trade_no'],//订单号
            'amount' => $orderData['total_fee'],//交易金额(分)
            'product' => '付费阅读' . $orderData['uid'],
            'productDesc' => '付费阅读' . $orderData['uid'],
            'attach' => $orderData['uid'],
            'payWay' => 'WEIXIN',
            'userIp' => $_SERVER['REMOTE_ADDR'],
            'notifyUrl' =>  $this->getNotifyUrl($qa), //后台回调地址
            'payType' => 'MINIAPP_WEIXIN', //支付类型
            'openId' => $openid,
        );
        // 生成签名
        $privateKey = $paymentNumber['private_key'];
        $inputOrderData['sign'] = getMhSign($inputOrderData, $privateKey);
        $encodeData = encryptData($inputOrderData, $privateKey);
        $postData = array(
            'merAccount' => $paymentNumber['mer_account'], // 商户标识
            'data' => $encodeData
        );
        // 请求米花接口下单接口
        $api_url = \MiHuaPayConfig::API_URL_CREATE_ORDER;
        $resstr = httpPost($api_url, http_build_query($postData));
        $res = json_decode($resstr, true);
        if (isset($res['code']) && $res['code'] == '000000') {
            $data['payInfo'] = json_decode($res['data']['payInfo'],true);
            return sucJson($data);
        } else {
            LogLogic::addLog('wxCreateOrder', $resstr, $orderData['uid'], $orderData['quick_id']);
            return errJson('下单失败：' . $res['msg']);
        }
    }

    private function getSignature($method, $url, $timestamp, $nonce, $data, $privateKey) {
        $targetStr = $method. "\n" . $url. "\n" . $timestamp. "\n" . $nonce. "\n" . $data. "\n";
        openssl_sign($targetStr, $sign, $privateKey, OPENSSL_ALGO_SHA256);
        $sign = base64_encode($sign);
        return $sign;
    }

    private function randStr($length = 8) {
        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $str = '';
        for ($i = 0; $i < $length; $i++) {
            $str .= $chars[mt_rand(0, strlen($chars) - 1)];
        }
        return $str;
    }


    private function getByteAuthorization($data, $appId, $nonceStr, $timestamp, $keyVersion) {
        $byteAuthorization = '';
        // 读取私钥
        $privateKey = Db::table('quick_private_key')->where('quick_appid', $appId)->value('private_key');
        if (!$privateKey) {
            throw new InvalidArgumentException("Invalid private key");
        }
        // 生成签名
        $signature = $this->getSignature("POST", "/requestOrder", $timestamp, $nonceStr, $data, $privateKey);
        if ($signature === false) {
            return null;
        }
        // 构造 byteAuthorization
        $byteAuthorization = sprintf("SHA256-RSA2048 appid=%s,nonce_str=%s,timestamp=%s,key_version=%s,signature=%s", $appId, $nonceStr, $timestamp, $keyVersion, $signature);
        return $byteAuthorization;
    }


    /**
     * 快手苹果支付
     *
     * @param $qa
     * @param $order
     * @return \think\response\Json
     * @throws \RedisException
     */
    private function ksIAP($qa, $order)
    {
        $url = 'https://open.kuaishou.com/openapi/mp/developer/epay/iap/create_order';
        $user = QuickUser::get($order['uid']);
        $help = new KsHelp();
        $client = new Client(['verify' => false]);
        $token = $help->getAccessToken($qa, $client);

        $params = [
            'out_order_no' => $order['out_trade_no'],
            'open_id' => $user->openid,
            'subject' => '付费阅读',
            'detail' => $order['order_desc'],
            'type' => 1273,
            'order_amount' => $order['total_fee'],
            'user_pay_amount' => $order['total_fee'],
            'expire_time' => 300,
            'notify_url' => $this->getNotifyUrl($qa),
            'refund_notify_url' => $this->refundNotifyUrl($qa),
        ];

        $params['sign'] = $help->createSign($params,$qa->appid,$qa->AppSecret);
        $url .= '?app_id=' . $qa->appid . '&access_token=' . $token;

        $result_json = $this->request_post($url,json_encode($params,JSON_UNESCAPED_UNICODE));
        $result = json_decode($result_json,true);

        if( isset($result['result']) && $result['result'] != 1){
            return errJson("code:" . $result['result'] . ",msg:" . $result['error_msg']);
        }

        return sucJson($result['order_info']);

    }

    private function ksCreateOrder($qa, $order) {
        $url = 'https://open.kuaishou.com/openapi/mp/developer/epay/create_order';
        $user = QuickUser::get($order['uid']);
        $help = new KsHelp();
        $client = new Client(['verify' => false]);
        $token = $help->getAccessToken($qa, $client);

        $params = [
            'out_order_no' => $order['out_trade_no'],
            'open_id' => $user->openid,
            'total_amount' => $order['total_fee'],
            'subject' => '付费阅读',
            'detail' => $order['order_desc'],
            'type' => 1273,
            'expire_time' => 300,
            'notify_url' => $this->getNotifyUrl($qa),
        ];

        $params['sign'] = $help->createSign($params,$qa->appid,$qa->AppSecret);
        $url .= '?app_id=' . $qa->appid . '&access_token=' . $token;

        $result_json = $this->request_post($url,json_encode($params,JSON_UNESCAPED_UNICODE));
        $result = json_decode($result_json,true);

        if( isset($result['result']) && $result['result'] != 1){
            return errJson("code:" . $result['result'] . ",msg:" . $result['error_msg']);
        }

        return sucJson($result['order_info']);
    }

    private function request_post( $url, $data, $timeout = 30 , $headers = [])
    {
        if (!$headers) {
            $headers = [
                'Accept: application/json',
                'Content-Type: application/json; charset=utf-8',
                'User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36',
            ];
        }

        $ch = curl_init();
        curl_setopt( $ch, CURLOPT_URL, $url );
        curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
        curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false );
        curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, false );
        curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, 10 );
        curl_setopt( $ch,CURLOPT_HTTPHEADER, $headers);
        curl_setopt( $ch, CURLOPT_TIMEOUT, $timeout ); // 设置超时限制防止死循环

        curl_setopt( $ch, CURLOPT_POST, 1 ); // 发送一个常规的Post请
        curl_setopt( $ch, CURLOPT_POSTFIELDS, is_string( $data ) ? $data : http_build_query( $data ) ); // Post提交的数据包求

        $result = curl_exec( $ch );
        curl_close( $ch );

        return $result;
    }



    /**
     * 抖音下单
     * @param $qa
     * @param $order
     * @return \think\response\Json
     * @throws \GuzzleHttp\Exception\GuzzleException
     * @Author: whh
     */
    private function dyCreateOrder($qa, $order)
    {
        $params = [
            'app_id' => $qa->appid,//小程序appid
            'out_order_no' => $order['out_trade_no'],
            'total_amount' => $order['total_fee'],
            'subject' => '付费阅读',
            'body' => $order['order_desc'],
            'valid_time' => 900, // 15分钟
            'notify_url' => $this->getNotifyUrl($qa),
        ];
        $help = new DouYinHelp();
        $params = array_filter($params);
        $params['sign'] = $help->sign($params, $qa->salt);
        $client = new Client(['verify' => false]);
        $url = "https://developer.toutiao.com/api/apps/ecpay/v1/create_order";
        $res = $client->request('POST', $url, [
            'json' => $params
        ]);
        $result = $res->getBody()->getContents();
        $result = json_decode($result, true);
        if ($result['err_no'] != 0) {
            return errJson("code:" . $result['err_no'] . ",msg:" . $result['err_tips']);
        }
        $user = QuickUser::get($order['uid']);
        $help->pushOrder($qa, $order, $user, $client);
        return sucJson($result['data']);
    }

    /**
     * 生成抖音client_token
     * @param $qa
     * @return false|mixed|\Redis|string
     */
    protected function getClientToken($qa) {
        $redis = new BehaviorRedis();
        $token = $redis->getDouyinClientToken($qa['appid']);
        if (!$token) {
            $url = 'https://open.douyin.com/oauth/client_token/';
            $data = [
                'client_key' => $qa['appid'],
                'client_secret' => $qa['AppSecret'],
                'grant_type' => 'client_credential'
            ];

            $result = json_decode(jhCurl($url, json_encode($data), 1, ['Content-Type:application/json']), true);
            if ($result['message'] != 'success') {
                return '';
            }
            $token = $result['data']['access_token'];
            $redis->setDouyinClientToken($qa['appid'], $token, $result['data']['expires_in']);
        }
        return $token;
    }

    /**
     * 回调地址
     * @param $qa
     * @return string
     * @throws \Exception
     * @Author: whh
     */
    public function getNotifyUrl($qa)
    {
        $apiDomain = config('api_domain');
        if ($qa->type == 1) {
            //抖音小程序
            return $apiDomain . "/notify/douyin";
        } elseif ($qa->type == 2) {
            //快手小程序
            return $apiDomain . "/notify/ks";
        } elseif ($qa->type == 3) {
            //微信小程序
            return $apiDomain . "/notify/mihuaWeixin";
        } else {
            throw new \Exception('小程序类型未知，获取回调链接失败');
        }
    }

    /**
     * 苹果支付退款回调地址
     *
     * @param $qa
     * @return string
     * @throws \Exception
     */
    public function refundNotifyUrl($qa)
    {
        $apiDomain = config('api_domain');
        if ($qa->type == 1) {
            //抖音小程序
            return $apiDomain . "/notify/douyinRefund";
        } elseif ($qa->type == 2) {
            //快手小程序
            return $apiDomain . "/notify/ksRefund";
        } else {
            throw new \Exception('小程序类型未知，获取回调链接失败');
        }
    }
}